feat(meter): add ecoflow-stream-mqtt with public-API MQTT and cascade discovery#29217
feat(meter): add ecoflow-stream-mqtt with public-API MQTT and cascade discovery#29217Metatron2k2 wants to merge 1 commit intoevcc-io:masterfrom
Conversation
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
CurrentPower, any error from a single device’s REST fallback aborts the whole reading; consider logging and skipping failing devices so transient REST issues for one unit don’t take down the aggregated meter. - The MQTT certification call in
ecoflow_mqtt.gouseshttp.DefaultClientwithout an explicit timeout; aligning this with the rest of the codebase by using a client withrequest.Timeout(or similar) would avoid potential hangs on slow/blocked networks.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `CurrentPower`, any error from a single device’s REST fallback aborts the whole reading; consider logging and skipping failing devices so transient REST issues for one unit don’t take down the aggregated meter.
- The MQTT certification call in `ecoflow_mqtt.go` uses `http.DefaultClient` without an explicit timeout; aligning this with the rest of the codebase by using a client with `request.Timeout` (or similar) would avoid potential hangs on slow/blocked networks.
## Individual Comments
### Comment 1
<location path="templates/definition/meter/ecoflow-stream-mqtt.yaml" line_range="47-34" />
<code_context>
+ help:
+ en: Secret Key from EcoFlow Developer Console
+ de: Secret Key aus der EcoFlow Developer Console
+ - name: serial
+ required: true
+ help:
+ en: Serial number of the main (master) device of your Stream system
</code_context>
<issue_to_address>
**question:** Template requires a serial even though the implementation supports discovery-only setups.
The Go constructor only errors when `Serial == "" && len(Serials) == 0 && !Discover`, so discovery-only use is supported. Marking `serial` as `required: true` in the template blocks this mode. If discovery-only setups should be allowed, make `serial` optional here or document that it must still be set even when `discover` is enabled.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
f033108 to
509fb9c
Compare
|
We should only have one implementation, not two. If we want this the other should be deprecated. Further, this needs be greatly simplified to use the evcc mqtt infrastructure, ideally reducing this to a template-only implementation. |
|
@andig Thanks for the feedback. I'm looking into it. |
8349c92 to
3ff2348
Compare
… discovery
Adds a dedicated device template for the EcoFlow Stream family that
uses EcoFlow's public-API MQTT broker for live data. The existing
`ecoflow-stream` template (REST-only via the generic `ecoflow` meter)
is kept untouched so no existing configuration changes behaviour.
Why
---
The REST `quota/all` endpoint returns a stale, largely aggregated
snapshot for Stream devices. Notably:
- individual PV string power (`powGetPv`..`powGetPv4`) is never
populated, only `powGetPvSum`, which includes output from unrelated
PV sources on the same cloud meter;
- battery power on the CMS level (`powGetBpCms`) is 0 for Stream AC
Hybrid installations;
- `cmsBattSoc` is always 0; the real per-module SoC lives in
`f32ShowSoc`;
- in cascade/multi-unit setups only the master's view is reachable
via REST.
Home Assistant's `hassio-ecoflow-cloud` integration gets these values
by subscribing to EcoFlow's public MQTT broker. evcc now does the
same.
What
----
- `meter/ecoflow_mqtt.go`: shared MQTT client for the EcoFlow public
API, one per (access key, region). HMAC-SHA256 signed certification
call to `/iot-open/sign/certification` via `request.NewClient`
(inherits `request.Timeout` and the instrumented transport), then
transport is delegated to evcc's shared `plugin/mqtt.Client` (same
path as `meter/zendure`). `plugin/mqtt` handles the Paho options,
TLS, reconnect and automatic re-subscription of every `Listen`ed
topic, so this file is limited to the EcoFlow-specific bits: cert
fetch, per-host stable client ID (hash of access key + hostname) to
respect EcoFlow's 10-unique-client-IDs/account/day quota while
letting prod and dev instances on the same account coexist,
per-serial `/open/<certificateAccount>/<sn>/quota` subscription,
and a payload parser that accepts both flat Stream objects and the
{"params":{...}} envelopes used by other device families.
- `meter/ecoflow_stream_mqtt.go`: new meter type
`ecoflow-stream-mqtt`. Responsibilities:
* map evcc usage (grid/pv/battery) to the right EcoFlow keys
(powGetSysGrid / powGetPv..4 / inputWatts-outputWatts +
f32ShowSoc);
* optionally discover sibling devices on the same account via
`/iot-open/sign/device/list`, matching by the 2-char serial
prefix so cascade systems (e.g. two Stream AC Hybrids linked
as master+slave) appear as one aggregated meter;
* subscribe each discovered serial to MQTT and cache the latest
values;
* prefer the MQTT cache for reads, fall back to per-serial REST
with `util.Cached`;
* sum CurrentPower across devices and return a plain-average
SoC, matching the cascade view shown in the EcoFlow app;
* tolerate per-device REST errors: a transient failure on one
cascade unit is logged and skipped so healthy devices keep
reporting; only when every device fails is the last error
surfaced.
- `templates/definition/meter/ecoflow-stream-mqtt.yaml`: new device
entry listed as "EcoFlow Stream (MQTT)". Exposes the same
access key / secret key / serial / usage inputs as `ecoflow-stream`
plus an advanced `discover` toggle (default true).
Verification
------------
Live-tested with a cascade of two EcoFlow Stream AC Hybrid units.
With a single configured master serial and discover=true, evcc now
reports:
[ecoflow-stream-mqtt] INFO discover: tracking 2 device(s): BK11...,BK31...
[site] pv 1 power: 593W
[site] battery 1 power: -1067W
[site] battery 1 soc: 37%
matching the EcoFlow mobile-app cascade view within the usual smoothing
lag. `go test ./...` and `golangci-lint run` are clean.
3ff2348 to
557e37d
Compare
|
@andig I moved it to the builtin client. Sorry for not doing this in the first place. Having it template only does not work, because of the HMAC Signing necessary for ecoflow. |
|
Hi @Metatron2k2 , I looked a little bit into your branch. The go-ecoflow lib also has a mqtt-client, so I think it would be much better to use this instead of vibe-coding a new one. Then you can probably reduce the meter a little bit more that could be enough. Keep in mind that the current implementation supports power ocean and stream. |
|
Hi @Kubiac, thanks for the Input. I'm not sure if using go-ecoflow is panning out here. The MQTT api of go-ecoflow uses the private api, which requires username and password instead of app tokens, so it would it is not compatible with the current auth method on the ecoflow devices. Without analyzing to far, it also seems like the Ocean is not supported by the private api (https://github.com/tolwi/hassio-ecoflow-cloud) . Also, you also noticed, that the go-ecoflow did not get any commits (besides adding a license file) in the last two years. With your PR over there not being looked at since mid march i would also assume the library has been abandoned. So all in all, using mqtt with the go-ecoflow library would nee about the same implementation (HMAC, etc.) as what my current client does, with the difference, that it would not use evccs mqtt implementation anymore. Looking at the Docu of the Ocean devices it should be pretty straight forward to port that to my client, or leave it as is. Fact is, that currently the Stream devices report very wron gata, whan there are orhter devices on the home elcetrical network and we need to fix it, if we want evcc to report the corect values. |
Summary
Adds a dedicated device template for the EcoFlow Stream family that uses EcoFlow's public-API MQTT broker for live data. The existing
ecoflow-streamtemplate (REST-only via the genericecoflowmeter) is kept untouched so no existing configuration changes behaviour.Why
The REST
quota/allendpoint returns a stale, largely aggregated snapshot for Stream devices. Notably:powGetPv..powGetPv4) is never populated, onlypowGetPvSum, which can include output from unrelated PV sources connected to the same cloud meter;powGetBpCms) is0for Stream AC Hybrid installations;cmsBattSocis always0; the real per-module SoC lives inf32ShowSoc;Home Assistant's
tolwi/hassio-ecoflow-cloudintegration gets these values by subscribing to EcoFlow's public MQTT broker. evcc now does the same.What
meter/ecoflow_mqtt.go— shared public-API MQTT client, one per(accessKey, region)./iot-open/sign/certification, TLS connection, subscribe to/open/<certificateAccount>/<sn>/quota.ecoflow-stream-mqttmeter so only one of EcoFlow's 10 unique-client-ID/day slots is consumed per account.accessKey + hostnameso dev and prod instances on the same account can coexist without disconnecting each other.{"params": {...}}/{"param": {...}}envelopes used by other device families.meter/ecoflow_stream_mqtt.go— new meter typeecoflow-stream-mqtt.grid→powGetSysGrid;pv→powGetPv..powGetPv4;battery→inputWatts - outputWattswithf32ShowSoc./iot-open/sign/device/list, matching by the 2-char serial prefix so cascade systems (e.g. two Stream AC Hybrids linked as master + slave) appear as one aggregated meter.util.Cached.CurrentPoweris the sum across devices;Socis the plain average, matching the EcoFlow app's cascade view.templates/definition/meter/ecoflow-stream-mqtt.yaml— new device entry listed as EcoFlow Stream (MQTT). Exposes the same access key / secret key / serial / usage inputs as the existingecoflow-streamtemplate, plus an advanceddiscovertoggle (defaulttrue).Backwards compatibility
Purely additive: no existing files are modified. The legacy
ecoflow-streamtemplate and the genericecoflowmeter remain byte-for-byte identical to master.Verification
Live-tested against a cascade of two EcoFlow Stream AC Hybrid units on one account. With a single configured master serial and
discover: true, evcc reports:Values match the EcoFlow mobile-app cascade view within the usual smoothing lag.
Test plan
make test— all Go tests pass, including themeterpackage.make lint— no new lint findings in the added files (the handful of warnings on master pre-date this PR).go vet ./meter/...— clean.make docs— regeneratestemplates/docs/{de,en}/meter/ecoflow-stream-mqtt.yaml(gitignored path, matching repo convention).go build ./...— binary built.inputWatts - outputWatts(negated), and averaged SoC all match the app.